# language: JSVM2

/**
 * @fileoverview com.homolo.commons.util.Calendar class {@link http://jsvm.org/}
 * @file		Calendar.jsc
 * @author	Wan Changhua
 * @version	2.01, 05/09/06
 * @since		JSVM2.02
 */

package com.homolo.commons.util;

import js.lang.ArgumentException;
import com.homolo.commons.util.TypeUtils;


/**
 * Inherit from JObject
 * @author	Wan Changhua
 * @version	2.01, 05/09/06
 * @extends js.lang.JObject
 * @class Calendar is a utility class for string
 * @constructor
 * @final
 */
class	Calendar (arg)
{
	if (TypeUtils.isNull(arg))
	{
		this.__date = new Date();
	}
	else if (TypeUtils.isDate(arg))
	{
		this.__date = new Date(arg.getTime());
	}
	else if (TypeUtils.isNumber(arg))
	{
		this.__date = new Date(arg);
	}
	else if (TypeUtils.isString(arg))
	{
		this.__date = Date.parse(arg);
	}
	else
	{
		throw new ArgumentException(this.getClass().getName()
			+ " (arg) argument error!");
	}
}


/**
 * Returns a new string that has been trimed
 * @param	  s   a string.
 * @type string
 */
Calendar.prototype.getTime = function()
{
	return this.__date.getTime();
}

Calendar.prototype.setTime = function(ms)
{
	return this.__date.setTime (ms);
}

/**
 * Returns the value of the given calendar field
 */
Calendar.prototype.get = function(field)
{
	var date = this.__date;
	switch (field)
	{
		//case Calendar.ERA : break;
		case Calendar.YEAR	:	return date.getFullYear();
		case Calendar.MONTH	:	return date.getMonth();
		case Calendar.WEEK_OF_YEAR	:
			var d0 = new Date(date.getFullYear(), 0, 1);
			var of = this.get(Calendar.DAY_OF_YEAR) + d0.getDay() - 1;
			return (of - (of % 7)) / 7 + 1;
		case Calendar.WEEK_OF_MONTH	:
			var d0 = new Date(date.getFullYear(), date.getMonth(), 1);
			var of = this.get(Calendar.DAY_OF_MONTH) + d0.getDay() - 1;
			return (of - (of % 7)) / 7 + 1;
		case Calendar.DATE	:
		case Calendar.DAY_OF_MONTH	:	return date.getDate();
		case Calendar.DAY_OF_YEAR	:	return Calendar.getUTCOffterDays(date) - Calendar.getUTCOffterDays(new Date(date.getFullYear(), 0, 1)) + 1;
		case Calendar.DAY_OF_WEEK	:	return date.getDay();
		case Calendar.DAY_OF_WEEK_IN_MONTH	:	return this.get(Calendar.WEEK_OF_MONTH);
		case Calendar.AM_PM	: return (date.getHours() >= 12) ? 1 : 0;
		case Calendar.HOUR	:	return date.getHours() % 12;
		case Calendar.HOUR_OF_DAY	:	return date.getHours();
		case Calendar.MINUTE	:	return date.getMinutes();
		case Calendar.SECOND	:	return date.getSeconds();
		case Calendar.MILLISECOND	:	return date.getMilliseconds();
		//case Calendar.ZONE_OFFSET = 15;
		//case Calendar.DST_OFFSET = 16;
		//case Calendar.FIELD_COUNT = 17;
		default : throw new ArgumentException(this.getClass().getName()
			+ ".roll(field, amount) field argument error: '" + field + "'");
	}
}

Calendar.prototype.set = function(field, value)
{
	var date = this.__date;
	switch (field)
	{
		//case Calendar.ERA : break;
		case Calendar.YEAR	:	date.setFullYear(value); break;
		case Calendar.MONTH	:	date.setMonth(value); break;
		case Calendar.WEEK_OF_YEAR	:
		case Calendar.WEEK_OF_MONTH	:	this.roll(Calendar.WEEK_OF_MONTH, value - this.get(Calendar.WEEK_OF_MONTH)); break;
		case Calendar.DATE	:
		case Calendar.DAY_OF_MONTH	:	date.setDate(value); break;
		case Calendar.DAY_OF_YEAR	:	this.roll(Calendar.DAY_OF_YEAR, value - this.get(Calendar.DAY_OF_YEAR)); break;
		case Calendar.DAY_OF_WEEK	:	date.setDay(value); break;
		case Calendar.DAY_OF_WEEK_IN_MONTH	:	this.set(Calendar.WEEK_OF_MONTH, value); break;
		case Calendar.AM_PM	: date.setHours(this.get(Calendar.HOUR) + ((value == 1) ? 12 : 0)); break;
		case Calendar.HOUR	:	date.setHours((date.setHours() >= 12 ? 0 : 12) + value); break;
		case Calendar.HOUR_OF_DAY	:	date.setHours(value); break;
		case Calendar.MINUTE	:	date.setMinutes(value); break;
		case Calendar.SECOND	:	date.setSeconds(value); break;
		case Calendar.MILLISECOND	:	date.setMilliseconds(value); break;
		//case Calendar.ZONE_OFFSET = 15;
		//case Calendar.DST_OFFSET = 16;
		//case Calendar.FIELD_COUNT = 17;
		default : throw new ArgumentException(this.getClass().getName()
			+ ".set(field, value) field argument error: '" + field + "'");
	}
}



Calendar.prototype.compareTo = function (o)
{
	if (o instanceof Calendar)
	{
		throw new ArgumentException(this.getClass().getName()
			+ ".compareTo(o) o argument is not Calendar object.");
	}
	var thisTime = this.getTime();
	var anorTime = o.getTime();
	return (thisTime > anorTime) ?
		1 : (thisTime == anorTime ? 0 : -1);
}

Calendar.prototype.equals = function (o)
{
	return (compareTo(o) == 0);
}

Calendar.prototype.before = function (o)
{
	return (compareTo(o) < 0);
}

Calendar.prototype.after = function (o)
{
	return (compareTo(o) > 0);
}

Calendar.prototype.toDate = function ()
{
	return new Date(this.getTime());
}


var SECOND_MILLISECONDS = 1000;
var MINUTE_MILLISECONDS = SECOND_MILLISECONDS * 60;
var HOUR_MILLISECONDS = MINUTE_MILLISECONDS * 60;
var DAY_MILLISECONDS = HOUR_MILLISECONDS * 24;
var WEEK_MILLISECONDS = DAY_MILLISECONDS * 7;


Calendar.prototype.roll = function (field, amount)
{
	var date = this.__date;
	switch (field)
	{
		//case Calendar.ERA : break;
		case Calendar.YEAR	:	date.setYear(date.getFullYear() + amount); break;
		case Calendar.MONTH	:	date.setMonth(date.getMonth() + amount); break;
		case Calendar.WEEK_OF_YEAR	:
		case Calendar.WEEK_OF_MONTH	:	date.setTime(date.getTime() + WEEK_MILLISECONDS * amount); break;
		case Calendar.DATE	:
		case Calendar.DAY_OF_MONTH	:
		case Calendar.DAY_OF_YEAR	:
		case Calendar.DAY_OF_WEEK	:	date.setTime(date.getTime() + DAY_MILLISECONDS * amount); break;
		case Calendar.DAY_OF_WEEK_IN_MONTH	:	this.roll(Calendar.WEEK_OF_YEAR, amount); break;
		//case Calendar.AM_PM = 9;
		//case Calendar.HOUR = 10;
		case Calendar.HOUR_OF_DAY	:	date.setHours(date.getHours() + amount); break;
		case Calendar.MINUTE	:	date.setMinutes(date.getMinutes() + amount); break;
		case Calendar.SECOND	:	date.setSeconds(date.getSeconds() + amount); break;
		case Calendar.MILLISECOND	:	date.setMilliseconds(date.getMilliseconds() + amount); break;
		//case Calendar.ZONE_OFFSET = 15;
		//case Calendar.DST_OFFSET = 16;
		//case Calendar.FIELD_COUNT = 17;
		default : throw new ArgumentException(this.getClass().getName()
			+ ".roll(field, amount) field argument error: '" + amount + "'");

	}
}

/**
 * Gets offer days of UTC
 * @param d0 Date
 * @type int
 */
Calendar.getUTCOffterDays = function (d0)
{
	var t0 = d0.getTime();
	var d1 = new Date(t0);
	d1.setYear(1900);
	d1.setMonth(0);
	d1.setDate(1);
	return (t0 - d1.getTime()) / DAY_MILLISECONDS ;
}




/**
 * @public static constant
 * @final
 */
Calendar.ERA = 0;
Calendar.YEAR = 1;
Calendar.MONTH = 2;
Calendar.WEEK_OF_YEAR = 3;
Calendar.WEEK_OF_MONTH = 4;
Calendar.DATE = 5;
Calendar.DAY_OF_MONTH = 5;
Calendar.DAY_OF_YEAR = 6;
Calendar.DAY_OF_WEEK = 7;
Calendar.DAY_OF_WEEK_IN_MONTH = 8;
Calendar.AM_PM = 9;
Calendar.HOUR = 10;
Calendar.HOUR_OF_DAY = 11;
Calendar.MINUTE = 12;
Calendar.SECOND = 13;
Calendar.MILLISECOND = 14;
Calendar.ZONE_OFFSET = 15;
Calendar.DST_OFFSET = 16;
Calendar.FIELD_COUNT = 17;
